﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Net;
using System.Security;
using System.Web;

namespace ADWebMonitor
{
    /// <summary>
    /// Summary description for RequestProxy1
    /// </summary>
    public class RequestProxy : IHttpHandler
    {
        #region Querystring Params

        /// <summary>
        /// Returns the url of the page to monitor
        /// </summary>
        /// <param name="context">The current httpcontext object</param>
        /// <returns>The requested Url from the querystring or an ArgumentNullException</returns>
        private string getRequestUrl(HttpContext context)
        {
            string requestUrl = context.Request.QueryString["Url"];

            if (requestUrl == null)
                throw new ArgumentNullException("Url");

            return requestUrl;
        
        }

        /// <summary>
        /// Returns the required content from the page to monitor
        /// </summary>
        /// <param name="context">The current httpcontext object</param>
        /// <returns>The requested Content from the querystring or an ArgumentNullException</returns>
        private string getrequiredResponse(HttpContext context)
        {
            string requiredResponse = context.Request.QueryString["Content"];

            if (requiredResponse == null)
                throw new ArgumentNullException("Content");

            return requiredResponse;

        }

        #endregion

        #region Settings and Application Cache Params

        private static int getProxyPort(HttpContext context)
        {
            string portSetting = cachedAppSetting(context, "ProxyPort");

            int port;
            if (Int32.TryParse(portSetting, out port))
            {
                return port;
            }
            else
                throw new ArgumentNullException("ProxyPort", "ProxyPort is a required integer Key in the AppSettings section of your web.config");
        }

        private static string encodeSecureTrace(string TextToTrace, bool secure)
        {
            if (secure)
            {
                System.Text.StringBuilder sb = new System.Text.StringBuilder();
                for (int i = 0; i < TextToTrace.Length; i++)
                {
                    sb.Append("*");
                }
                return sb.ToString();
            }
            else
            {
                return TextToTrace;
            }
        }
     
        private static string cachedAppSetting(HttpContext context, string settingName)
        {
            return cachedAppSetting(context, settingName, false);
        }

        private static string cachedAppSetting(HttpContext context, string settingName, bool secure)
        {
            string settingValue;

            //get the value from application scope
            object appSetting = context.Application[settingName];

             

            if (appSetting != null)
            {
                settingValue =  appSetting.ToString();
                context.Trace.Write("Settings", settingName + ":  " + encodeSecureTrace(settingValue, secure) + " found in cache");
                return settingValue;
            }
            else
            {
                
                settingValue = ConfigurationManager.AppSettings[settingName];

                if (settingValue != null)
                {
                    if (!secure)
                    {
                        //cache the value in application scope
                        context.Application[settingName] = settingValue;
                        context.Trace.Write("Settings", settingName + ":  " + encodeSecureTrace(settingValue, secure) + " added to cache");
                    }
                    else
                        context.Trace.Write("Settings", settingName + ":  " + encodeSecureTrace(settingValue, secure) + " not cached for security");
                        return settingValue;
                }
                else
                    throw new ArgumentNullException(settingName, settingName + " is a required Key in the AppSettings section of your web.config");
            }
        }

        public enum AuthMode { WorkerProcess = 1, WebConfig=2 };

        private static AuthMode getAuthMode(HttpContext context)
        {
            string authMode = cachedAppSetting(context, "AuthMode");

            if (authMode == "WebConfig")
                return AuthMode.WebConfig;
            else
                return AuthMode.WorkerProcess;

        }

        private static bool useProxy(HttpContext context)
        {
            bool result;
            string use = cachedAppSetting(context, "UseProxy");

            if (!Boolean.TryParse(use, out result))
                result = false;

            return result;
        }

       

        private static string getDomain(HttpContext context)
        {
            return  cachedAppSetting(context, "Domain");;
        }

        private static string getPassword(HttpContext context)
        {
            return cachedAppSetting(context, "Password",true);
        }

        private static string getUserName(HttpContext context)
        {
            return cachedAppSetting(context, "UserName");
        }

        #endregion

        #region Configure WebRequest, ResponseText, Proxy & CredentialCache Objects

        private WebProxy getProxy(HttpContext context)
        {
            return new WebProxy(cachedAppSetting(context, "ProxyHost"), Int32.Parse(cachedAppSetting(context, "ProxyPort")));
        }

        private CredentialCache getCredentialCache(HttpContext context)
        {
            CredentialCache credentialCache = new CredentialCache();

            
            NetworkCredential creds = new NetworkCredential(getUserName(context), getPassword(context), getDomain(context));
            
            credentialCache.Add(new Uri(getRequestUrl(context)), "NTLM", creds);
            
            return credentialCache;
        }

        private WebRequest getWebRequest(HttpContext context)
        {
            //the credential cache will associate the credentials with the requested url
            CredentialCache credentialCache = getCredentialCache(context);

            WebRequest request = WebRequest.Create(getRequestUrl(context));

            request.ImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.None;
            request.UseDefaultCredentials = true;
            request.PreAuthenticate = true;

            if (getAuthMode(context) == AuthMode.WebConfig)
            {
                request.Credentials = credentialCache;
            }
                        
            if (useProxy(context))
                request.Proxy = getProxy(context);

            return request;
        }

        private static string getResponseText(WebRequest request)
        {
            WebResponse response = request.GetResponse();
            System.IO.StreamReader reader = new System.IO.StreamReader(response.GetResponseStream());
            string responseText = reader.ReadToEnd();
            return responseText;
        }

        #endregion

        #region Success and Error Handling

        private static void error(HttpContext context, WebException ex)
        {
            throw (ex);
        }

        private void error(HttpContext context)
        {
            context.Response.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
            context.Response.Write("ERROR:  " + getrequiredResponse(context) + " not found in content");
        }

        private void success(HttpContext context)
        {
            context.Response.StatusCode = (int)System.Net.HttpStatusCode.OK;
            context.Response.Write(getrequiredResponse(context) + " found within Url: " + getRequestUrl(context));
        }

        #endregion

        public void ProcessRequest(HttpContext context)
        {
            context.Response.ContentType = "text/plain";

            WebRequest request = getWebRequest(context);

            try
            {
                string responseText = getResponseText(request);

                if (responseText.Contains(getrequiredResponse(context)))
                {
                    success(context);
                }
                else
                {
                    error(context);
                }
            }
            catch (System.Net.WebException ex)
            {
                error(context, ex);
            }
          
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}